package org.epanetgrid.relatorios.common;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.epanetgrid.resultado.output.DefaultErrorRelatorio;
import org.epanetgrid.resultado.output.DefaultOutPutRelatorio;

public class ExportXLS {

	private static final String MALHA_LABEL = "Malha";
	
	private static final String DATA_LABEL = "Data da simulação";
	private static final String CUSTO_TOTAL_LABEL = "Custo total";
	private static final String ALARMES_LABEL = "Alarmes";
	
	private static final String PRESSAO_MIN_LABEL = "Pressão mínima [Pa]";
	private static final String PRESSAO_MAX_LABEL = "Pressão máxima [Pa]";
	
	private static final String VELOCIDADE_MIN_LABEL = "Velocidade mínima [m/s]";
	private static final String VELOCIDADE_MAX_LABEL = "Velocidade máxima [m/s]";
	
	private static final String ELEMENTO_LABEL = "Elemento";
	
	private static final String TEMPOS_WS_LABEL = "Tempos";
	private static final String POP_WS_LABEL = "População Final";
	private static final String POP_RED_WS_LABEL = "População Final Reduzida";
	
	private static final String FO1_GLOBAL_LABEL = "FO1 Global";
	private static final String FO1_VIAVEL_LABEL = "FO1 Viavel";
	
	private static final String FO2_GLOBAL_LABEL = "FO2 Global";
	private static final String FO2_VIAVEL_LABEL = "FO2 Viavel";
	
	private static final String FO3_GLOBAL_LABEL = "FO3 Global";
	private static final String FO3_VIAVEL_LABEL = "FO3 Viavel";

	private HSSFSheet fo1GlobalWS;
	private int fo1GlobalRow;
	
	private HSSFSheet fo1ViavelWS;
	private int fo1ViavelRow;
	
	private HSSFSheet fo2GlobalWS;
	private int fo2GlobalRow;
	
	private HSSFSheet fo2ViavelWS;
	private int fo2ViavelRow;

	private HSSFSheet fo3GlobalWS;
	private int fo3GlobalRow;

	private HSSFSheet fo3ViavelWS;
	private int fo3ViavelRow;

	private HSSFSheet popWs;
	private int popRow;

	private HSSFSheet popRedWs;
	private int popRedRow;

	private HSSFSheet temposWs;

	private int temposRow;

	private int objetivos;

	private HSSFWorkbook wb;

	public ExportXLS(int objetivos) {
		wb = new HSSFWorkbook();
		this.objetivos = objetivos;

		switch (objetivos) {
		case 3: // Nao break, precisa das 3 planilhas
			fo3GlobalWS = wb.createSheet(FO3_GLOBAL_LABEL);
			fo3ViavelWS = wb.createSheet(FO3_VIAVEL_LABEL);
			fo3GlobalRow = 0;
			fo3ViavelRow = 0;
		case 2:// Nao break, precisa das 2 planilhas
			fo2GlobalWS = wb.createSheet(FO2_GLOBAL_LABEL);
			fo2ViavelWS = wb.createSheet(FO2_VIAVEL_LABEL);
			fo2GlobalRow = 0;
			fo2ViavelRow = 0;
		case 1:
			fo1GlobalWS = wb.createSheet(FO1_GLOBAL_LABEL);			
			fo1ViavelWS = wb.createSheet(FO1_VIAVEL_LABEL);
			fo1GlobalRow = 0;
			fo1ViavelRow = 0;
			break;
		default:
			break;
		}
		
		popWs = wb.createSheet(POP_WS_LABEL);
		popRow = 0;
		popRedWs = wb.createSheet(POP_RED_WS_LABEL);
		popRedRow = 0;
		
		switch (objetivos) {
		case 1:
			addLabel(fo1GlobalWS, fo1GlobalRow++, "Geração", "FO1", "Ponto de falha", "Cromossomo");
			addLabel(fo1ViavelWS, fo1ViavelRow++, "Geração", "FO1", "Ponto de falha", "Cromossomo");
			addLabel(popWs, popRow++,"Solução", "FO1", "Ponto de falha", "Cromossomo");
			addLabel(popRedWs, popRedRow++,"Solução", "FO1", "Ponto de falha", "Cromossomo");
			break;
		case 2:
			addLabel(fo1GlobalWS, fo1GlobalRow++, "Geração", "FO1", "FO2", "Ponto de falha", "Cromossomo");
			addLabel(fo1ViavelWS, fo1ViavelRow++, "Geração", "FO1", "FO2", "Ponto de falha", "Cromossomo");
			addLabel(fo2GlobalWS, fo2GlobalRow++, "Geração", "FO1", "FO2", "Ponto de falha", "Cromossomo");
			addLabel(fo2ViavelWS, fo2ViavelRow++, "Geração", "FO1", "FO2", "Ponto de falha", "Cromossomo");
			addLabel(popWs, popRow++,"Solução", "FO1", "FO2", "Ponto de falha", "Cromossomo");
			addLabel(popRedWs, popRedRow++,"Solução", "FO1", "FO2", "Ponto de falha", "Cromossomo");
			break;
		case 3:
			addLabel(fo1GlobalWS, fo1GlobalRow++, "Geração", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(fo1ViavelWS, fo1ViavelRow++, "Geração", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(fo2GlobalWS, fo2GlobalRow++, "Geração", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(fo2ViavelWS, fo2ViavelRow++, "Geração", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(fo3GlobalWS, fo3GlobalRow++, "Geração", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(fo3ViavelWS, fo3ViavelRow++, "Geração", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(popWs, popRow++,"Solução", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			addLabel(popRedWs, popRedRow++,"Solução", "FO1", "FO2", "F03", "Ponto de falha", "Cromossomo");
			break;
		default:
			addLabel(popWs, popRow++,"Solução", "Ponto de falha", "Cromossomo");
			addLabel(popRedWs, popRedRow++,"Solução", "Ponto de falha", "Cromossomo");
			break;
		}
		temposWs = wb.createSheet(TEMPOS_WS_LABEL);
		temposRow = 0;
	}
	
	private void addLabel(HSSFSheet sheet, int rowNumber, String ...labels) {
		HSSFRow row = sheet.createRow(rowNumber);
		short celValue  = 0;
		for (String label : labels) {
			row.createCell(celValue++).setCellValue(new HSSFRichTextString(label));
		}
	}

	public void inserirTempo(String nome, String data, String tempo) {
		HSSFRow row = temposWs.createRow(temposRow++);
		
		row.createCell((short) 0).setCellValue(new HSSFRichTextString(nome));
		row.createCell((short) 1).setCellValue(new HSSFRichTextString(data));
		row.createCell((short) 2).setCellValue(new HSSFRichTextString(tempo));
	}
	
	public void inserirFO1Global(int geracao, double fo1, double fo2, double fo3, long pf, String cromossomo) {
		inserirCromossomo(fo1GlobalWS, fo1GlobalRow++, geracao, fo1, fo2, fo3, pf, cromossomo);
	}
	
	public void inserirFO1Viavel(int geracao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(fo1ViavelWS, fo1ViavelRow++, geracao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}
	
	public void inserirFO2Global(int geracao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(fo2GlobalWS, fo2GlobalRow++, geracao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}
	
	public void inserirFO2Viavel(int geracao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(fo2ViavelWS, fo2ViavelRow++, geracao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}

	public void inserirFO3Global(int geracao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(fo3GlobalWS, fo3GlobalRow++, geracao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}
	
	public void inserirFO3Viavel(int geracao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(fo3ViavelWS, fo3ViavelRow++, geracao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}

	public void inserirPopulacao(int solucao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(popWs, popRow++, solucao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}
	
	public void inserirPopulacaoRed(int solucao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		inserirCromossomo(popRedWs, popRedRow++, solucao, fo1, fo2, fo3, pontoDeFalha, cromossomo);
	}
	
	private void inserirCromossomo(HSSFSheet sheet, int rowNumber, int geracao, double fo1, double fo2, double fo3, long pontoDeFalha, String cromossomo) {
		HSSFRow row = sheet.createRow(rowNumber);
		short cellValor = 0;
		row.createCell(cellValor++).setCellValue(geracao);
		switch (objetivos) {
		case 1:
			row.createCell(cellValor++).setCellValue(fo1);
			break;
		case 2:
			row.createCell(cellValor++).setCellValue(fo1);
			row.createCell(cellValor++).setCellValue(fo2);
			break;
		case 3:
			row.createCell(cellValor++).setCellValue(fo1);
			row.createCell(cellValor++).setCellValue(fo2);
			row.createCell(cellValor++).setCellValue(fo3);
			break;
		default:
			break;
		}
		row.createCell(cellValor++).setCellValue(pontoDeFalha);
		row.createCell(cellValor++).setCellValue(new HSSFRichTextString(cromossomo));
	}
	
	
	/**
	 * @param outPutRelatorio
	 * @return
	 */
	public HSSFWorkbook createSheet(Map<DefaultOutPutRelatorio, DefaultErrorRelatorio>  reports) {
		
		HSSFWorkbook wb = new HSSFWorkbook();

		HSSFSheet sheet = wb.createSheet("Simulacao");
		sheet.setDefaultColumnWidth((short) (sheet.getDefaultColumnWidth() * 2));

		HSSFRow row = sheet.createRow(0);
		
		row.createCell((short) 0).setCellValue(MALHA_LABEL);
		row.createCell((short) 1).setCellValue(DATA_LABEL);
		row.createCell((short) 2).setCellValue(CUSTO_TOTAL_LABEL);
		row.createCell((short) 3).setCellValue(ALARMES_LABEL);
		
		
		int count = 1;
		for (Entry<DefaultOutPutRelatorio, DefaultErrorRelatorio> entry : reports.entrySet()) {
			
			HSSFRow rowTemp = sheet.createRow(count);
			DefaultErrorRelatorio resultRelatorio = entry.getValue();
			DefaultOutPutRelatorio outRelatorio = entry.getKey();
			
			rowTemp.createCell((short) 0).setCellValue("Malha "+count++);
			rowTemp.createCell((short) 1).setCellValue(outRelatorio.getDataSimulacao().toString());
			rowTemp.createCell((short) 2).setCellValue(outRelatorio.getCusto().getEstimatedValue() + "");
			rowTemp.createCell((short) 3).setCellValue(resultRelatorio.getAlarmes().size() + "");
		}

		
		sheet = wb.createSheet("Pressao");
		sheet.setDefaultColumnWidth((short) (sheet.getDefaultColumnWidth() * 2));

		row = sheet.createRow(0);
		
		row.createCell((short) 0).setCellValue(MALHA_LABEL);
		row.createCell((short) 1).setCellValue(PRESSAO_MIN_LABEL);
		row.createCell((short) 2).setCellValue(ELEMENTO_LABEL);
		row.createCell((short) 3).setCellValue(PRESSAO_MAX_LABEL);
		row.createCell((short) 4).setCellValue(ELEMENTO_LABEL);
		
		
		count = 1;
		for (Entry<DefaultOutPutRelatorio, DefaultErrorRelatorio> entry : reports.entrySet()) {
			
			HSSFRow row2 = sheet.createRow(count);
			DefaultOutPutRelatorio outPutRelatorio = entry.getKey();
			
			row2 = sheet.createRow(count);
			
			row2.createCell((short) 0).setCellValue("Malha "+count++);
//			row2.createCell((short) 1).setCellValue(outPutRelatorio.pressaoMinimaNode().getPressao().getEstimatedValue()+"");
//			row2.createCell((short) 2).setCellValue(outPutRelatorio.pressaoMinimaNode().getNodeName());
//			row2.createCell((short) 3).setCellValue(outPutRelatorio.pressaoMaximaNode().getPressao().getEstimatedValue()+"");
//			row2.createCell((short) 4).setCellValue(outPutRelatorio.pressaoMaximaNode().getNodeName());
		}
		
		
		//malha velo_min. elem. velo_max. elem.
		sheet = wb.createSheet("Velocidade");
		sheet.setDefaultColumnWidth((short) (sheet.getDefaultColumnWidth() * 2));

		row = sheet.createRow(0);
		
		row.createCell((short) 0).setCellValue(MALHA_LABEL);
		row.createCell((short) 1).setCellValue(VELOCIDADE_MIN_LABEL);
		row.createCell((short) 2).setCellValue(ELEMENTO_LABEL);
		row.createCell((short) 3).setCellValue(VELOCIDADE_MAX_LABEL);
		row.createCell((short) 4).setCellValue(ELEMENTO_LABEL);
		
		
		count = 1;
		for (Entry<DefaultOutPutRelatorio, DefaultErrorRelatorio> entry : reports.entrySet()) {
			
			HSSFRow row2 = sheet.createRow(count);
			DefaultOutPutRelatorio outPutRelatorio = entry.getKey();
			
			row2 = sheet.createRow(count);
			
			row2.createCell((short) 0).setCellValue("Malha "+count++);
//			row2.createCell((short) 1).setCellValue(outPutRelatorio.velocidadeMinimaNode().getVelocidade().getEstimatedValue()+"");
//			row2.createCell((short) 2).setCellValue(outPutRelatorio.velocidadeMinimaNode().getNodeName());
//			row2.createCell((short) 3).setCellValue(outPutRelatorio.velocidadeMaximaNode().getVelocidade().getEstimatedValue()+"");
//			row2.createCell((short) 4).setCellValue(outPutRelatorio.velocidadeMaximaNode().getNodeName());
		}
		
		return wb;
	}
	
	public void exportResults(File file) {

		FileOutputStream fileOut;
		try {
			fileOut = new FileOutputStream(file);
			wb.write(fileOut);
			fileOut.close();
		} catch (IOException e) {
			e.printStackTrace();
			throw new IllegalArgumentException(e.getMessage());
		}
	}

	public void resetPopulacao() {
		this.popRow = 1;
	}
	
	public void resetPopulacaoRed() {
		this.popRedRow = 1;
	}
	
}
